/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package tpgen.manchester.w3org;

import java.util.ArrayList;
import java.util.List;
import tpgen.grammar.Alt;
import tpgen.grammar.Grammar;
import tpgen.grammar.NonTerminal;
import tpgen.grammar.RandomVariable;
import tpgen.grammar.Symbol;
import tpgen.grammar.Terminal;

/**
 *
 * @author shanki
 */
public class W3OrgManchesterGrammar extends Grammar {
    private final NonTerminal frame;
    private final List<Symbol> variableTypes = new ArrayList<Symbol>();    

    
    
    @Override
    public Symbol getStartSymbol() {
        return frame;
    }

    @Override
    public List<Symbol> getVariableTypes() {
        return variableTypes;
    }
    
    
    public W3OrgManchesterGrammar(ManchesterPropability p) {
        Alt dataType    = new Alt();
        dataType.add(new Terminal("integer"), 1);
        dataType.add(new Terminal("decimal"), 1);
        dataType.add(new Terminal("float"), 1);
        dataType.add(new Terminal("string"), 1);
        
        
        Terminal comma      = new Terminal(",");
        Terminal some       = new Terminal("some");
        Terminal only       = new Terminal("only");
        Terminal value      = new Terminal("value");
        Terminal min        = new Terminal("min");
        Terminal exactly    = new Terminal("exactly");
        Terminal max        = new Terminal("max");
        Terminal lpar       = new Terminal("(");
        Terminal rpar       = new Terminal(")");
        Terminal or         = new Terminal("or");
        Terminal and        = new Terminal("and");
        Terminal not        = new Terminal("not");
        Terminal o          = new Terminal("o");
        Terminal lcurl      = new Terminal("{");
        Terminal rcurl      = new Terminal("}");
        Terminal self       = new Terminal("self");
        Terminal inverse    = new Terminal("inverse");
        Terminal lsq        = new Terminal("[");
        Terminal rsq        = new Terminal("]");
        Terminal length     = new Terminal("length");
        Terminal minLength  = new Terminal("minLength");
        Terminal maxLength  = new Terminal("maxLength");
        Terminal pattern    = new Terminal("pattern");
        Terminal langRange  = new Terminal("langRange");
        Terminal leq        = new Terminal("&lt;=");
        Terminal less       = new Terminal("&lt;");
        Terminal geq        = new Terminal("&gt;=");
        Terminal greater    = new Terminal("&gt;");
        
        Terminal classT                 = new Terminal("Class:");
        Terminal objectProperty         = new Terminal("ObjectProperty:");
        Terminal dataProperty           = new Terminal("DataProperty:");
        Terminal individualT            = new Terminal("Individual:");        
        Terminal characteristics        = new Terminal("Characteristics:");
        Terminal subClassOf             = new Terminal("SubClassOf:");
        Terminal equivalentTo           = new Terminal("EquivalentTo:");
        Terminal disjointWith           = new Terminal("DisjointWith:");
        Terminal disjointUnionOf        = new Terminal("DisjointUnionOf:");
        Terminal subPropertyOf          = new Terminal("SubPropertyOf:");
        Terminal subPropertyChain       = new Terminal("SubPropertyChain:");
        Terminal inverseOf              = new Terminal("InverseOf:");
        Terminal range                  = new Terminal("Range:");
        Terminal domain                 = new Terminal("Domain:");
        Terminal types                  = new Terminal("Types:");
        Terminal facts                  = new Terminal("Facts:");
        Terminal sameAs                 = new Terminal("SameAs:");
        Terminal differentFrom          = new Terminal("DifferentFrom:");
        
        Terminal functional             = new Terminal("Functional");
        Terminal symmetric              = new Terminal("Symmetric");
        Terminal asymmetric             = new Terminal("Asymmetric");
        Terminal reflexive              = new Terminal("Reflexive");
        Terminal transitive             = new Terminal("Transitive");
        Terminal irreflexive            = new Terminal("Irreflexive");
        Terminal inverseFunctional      = new Terminal("InverseFunctional");
        
//        Terminal equivalentClasses      = new Terminal("EquivalentClasses:");
//        Terminal disjointClasses        = new Terminal("DisjointClasses:");
//        Terminal equivalentProperties   = new Terminal("EquivalentProperties:");
//        Terminal disjointProperties     = new Terminal("DisjointProperties:");
//        Terminal sameIndividual         = new Terminal("SameIndividual:");
//        Terminal differentIndividuals   = new Terminal("DifferentIndividuals:");
        
        RandomVariable classIRI             = new RandomVariable("Class");
        variableTypes.add(classIRI);
        RandomVariable objectPropertyIRI    = new RandomVariable("ObjectProperty");
        variableTypes.add(objectPropertyIRI);
        RandomVariable dataPropertyIRI      = new RandomVariable("DatatypeProperty");
        variableTypes.add(dataPropertyIRI);
        RandomVariable individual           = new RandomVariable("Individual");
        variableTypes.add(individual);
        RandomVariable literal              = new RandomVariable("Literal");
        variableTypes.add(literal);
        RandomVariable nonNegativeInteger   = literal;        

        NonTerminal description = new NonTerminal("description");
        NonTerminal primary     = new NonTerminal("primary");
        NonTerminal dataRange   = new NonTerminal("dataRange");

        NonTerminal literalList         = nt("literalList", list(literal, comma, p.get(Construct.list2Next)));
        NonTerminal descriptionList     = nt("descriptionList", list(description, comma, p.get(Construct.listNext)));
//        NonTerminal description2List    = nt("description2List", listMin2(description, comma, p.get(Construct.list2Next)));
        NonTerminal dataRangeList       = nt("dataRangeList", list(dataRange, comma, p.get(Construct.listNext)));
        NonTerminal individualList      = nt("individualList", list(individual, comma, p.get(Construct.listNext)));
        NonTerminal individualList2     = nt("individualList", list(individual, comma, p.get(Construct.twoListNext)));
//        NonTerminal individual2List     = nt("individual2List", listMin2(individual, comma, p.get(Construct.list2Next)));
//        NonTerminal objectProperty2List = nt("objectProperty2List", listMin2(objectPropertyIRI, comma, p.get(Construct.list2Next)));
//        NonTerminal dataProperty2List   = nt("dataProperty2List", listMin2(dataPropertyIRI, comma, p.get(Construct.list2Next)));
        
        NonTerminal classIRIList        = nt("classIRIList", list(classIRI, comma, p.get(Construct.list2Next)));

        NonTerminal inverseObjectProperty = nt("inverseObjectProperty", seq(inverse, objectPropertyIRI));
        
        Alt objectPropertyExpressionBody = new Alt();
        objectPropertyExpressionBody.add(objectPropertyIRI, 1);
        objectPropertyExpressionBody.add(inverseObjectProperty, p.get(Construct.objectPropertyExpressionInverse));
        
        NonTerminal objectPropertyExpression = nt("objectPropertyExpression", objectPropertyExpressionBody);  
        NonTerminal objectPropertyExpressionList    = nt("objectPropertyExpressionList", list(objectPropertyExpression, comma, p.get(Construct.listNext)));
        
        NonTerminal dataPropertyExpression = nt("dataPropertyExpression", dataPropertyIRI);
        NonTerminal dataPropertyExpressionList  = nt("dataPropertyExpressionList", list(dataPropertyExpression, comma, p.get(Construct.listNext)));
        
        Alt facetBody = new Alt();
        facetBody.add(length, 1);
        facetBody.add(minLength, 1);
        facetBody.add(maxLength, 1);
        facetBody.add(pattern, 1);
        facetBody.add(langRange, 1);
        facetBody.add(leq, 1);
        facetBody.add(less, 1);
        facetBody.add(geq, 1);
        facetBody.add(greater, 1);
                
        NonTerminal facet = nt("facet", facetBody);        
        NonTerminal restrictionValue = nt("restrictionValue", literal);        
        NonTerminal dataTypeRestriction = nt("dataTypeRestriction", seq(dataType, lsq, facet, restrictionValue, rep(seq(comma, facet, restrictionValue), true, p.get(Construct.list2Next)) ,rsq));
        
        Alt dataAtomicBody = new Alt();
        dataAtomicBody.add(dataType, 1);
        dataAtomicBody.add(seq(lcurl, literalList, rcurl), p.get(Construct.dataAtomicLiteralList));
        dataAtomicBody.add(dataTypeRestriction, p.get(Construct.dataAtomicDataTypeRestriction));
        //dataAtomicBody.add(seq(lpar, dataRange, rpar), 1);
        dataAtomicBody.add(dataRange, 1);
        
        
        NonTerminal dataAtomic = nt("dataAtomic", dataAtomicBody);
        
        NonTerminal dataPrimary = nt("dataPrimary", seq(opt(not, p.get(Construct.dataPrimaryNot)), dataAtomic));
        
        Alt dataConjunctionAlt  = new Alt();
        double pDataConjunctionAnd = p.get(Construct.dataConjunctionAnd);
        dataConjunctionAlt.add(seq(lpar, dataPrimary, rpar, and, lpar, dataPrimary, rpar, rep(seq(and, lpar, dataPrimary, rpar), true, pDataConjunctionAnd)), pDataConjunctionAnd);
        dataConjunctionAlt.add(dataPrimary, 1 - pDataConjunctionAnd);
        
        //NonTerminal dataConjunction = nt("dataConjunction", seq(dataPrimary, rep(seq(and, dataPrimary), true, p.get(Construct.dataConjunctionAnd))));        
        NonTerminal dataConjunction = nt("dataConjunction", dataConjunctionAlt);
        
        Alt dataRangeAlt    = new Alt();
        double pDataRangeOr = p.get(Construct.dataRangeOr);
        dataRangeAlt.add(seq(lpar, dataConjunction, rpar, or, lpar, dataConjunction, rpar, rep(seq(or, lpar, dataConjunction, rpar), true, pDataRangeOr)), pDataRangeOr);
        dataRangeAlt.add(dataConjunction, 1 - pDataRangeOr);
        
        dataRange.setSymbol(seq(dataConjunction, rep(seq(or, dataConjunction), true, p.get(Construct.dataRangeOr))));
        //dataRange.setSymbol(seq(dataConjunction, rep(seq(or, dataConjunction), true, p.get(Construct.dataRangeOr))));
        
        Alt restrictionBody = new Alt();
        restrictionBody.add(seq(objectPropertyExpression, some, lpar, primary, rpar), p.get(Construct.restrictionObjectSome));
        restrictionBody.add(seq(objectPropertyExpression, only, lpar, primary, rpar), p.get(Construct.restrictionObjectOnly));
        restrictionBody.add(seq(objectPropertyExpression, value, individual), p.get(Construct.restrictionObjectValue));
        restrictionBody.add(seq(objectPropertyExpression, self), p.get(Construct.restrictionObjectSelf));
//        restrictionBody.add(seq(objectPropertyExpression, min, nonNegativeInteger, opt(lpar, primary, rpar, p.get(Construct.restrictionObjectPrimary))), p.get(Construct.restrictionObjectMin));
//        restrictionBody.add(seq(objectPropertyExpression, max, nonNegativeInteger, opt(lpar, primary, rpar, p.get(Construct.restrictionObjectPrimary))), p.get(Construct.restrictionObjectMax));
//        restrictionBody.add(seq(objectPropertyExpression, exactly, nonNegativeInteger, opt(lpar, primary, rpar, p.get(Construct.restrictionObjectPrimary))), p.get(Construct.restrictionObjectExactly));
        restrictionBody.add(seq(objectPropertyExpression, min, nonNegativeInteger, classIRI), p.get(Construct.restrictionObjectMin));
        restrictionBody.add(seq(objectPropertyExpression, max, nonNegativeInteger, classIRI), p.get(Construct.restrictionObjectMax));
        restrictionBody.add(seq(objectPropertyExpression, exactly, nonNegativeInteger, classIRI), p.get(Construct.restrictionObjectExactly));
        restrictionBody.add(seq(dataPropertyExpression, some, lpar, dataPrimary, rpar), p.get(Construct.restrictionDataSome));
        restrictionBody.add(seq(dataPropertyExpression, only, lpar, dataPrimary, rpar), p.get(Construct.restrictionDataOnly));
        restrictionBody.add(seq(dataPropertyExpression, value, literal), p.get(Construct.restrictionDataValue));
//        restrictionBody.add(seq(dataPropertyExpression, min, nonNegativeInteger, opt(dataPrimary, p.get(Construct.restrictionDataPrimary))), p.get(Construct.restrictionDataMin));
//        restrictionBody.add(seq(dataPropertyExpression, max, nonNegativeInteger, opt(dataPrimary, p.get(Construct.restrictionDataPrimary))), p.get(Construct.restrictionDataMax));
//        restrictionBody.add(seq(dataPropertyExpression, exactly, nonNegativeInteger, opt(dataPrimary, p.get(Construct.restrictionDataPrimary))), p.get(Construct.restrictionDataExactly));
        restrictionBody.add(seq(dataPropertyExpression, min, nonNegativeInteger, dataType), p.get(Construct.restrictionDataMin));
        restrictionBody.add(seq(dataPropertyExpression, max, nonNegativeInteger, dataType), p.get(Construct.restrictionDataMax));
        restrictionBody.add(seq(dataPropertyExpression, exactly, nonNegativeInteger, dataType), p.get(Construct.restrictionDataExactly));
        
        NonTerminal restriction = nt("restriction", restrictionBody);
        
        Alt atomicBody  = new Alt();
        atomicBody.add(classIRI, 1);
        atomicBody.add(seq(lcurl, individualList2, rcurl), p.get(Construct.atomicIndividualList));
        //atomicBody.add(seq(lpar, description, rpar), 1);
        atomicBody.add(description, 1);
        
        NonTerminal atomic = nt("atomic", atomicBody);
        
        
        Alt primaryAlt  = new Alt();
        primaryAlt.add(atomic, 1);
        primaryAlt.add(restriction, 1);
        
        primary.setSymbol(seq(opt(not, p.get(Construct.primaryNot)), primaryAlt));
        
        Alt conjunctionBody = new Alt();
        //conjunctionBody.add(seq(primary, rep(seq(and, primary), true, p.get(Construct.conjunctionAnd))), 1);
        double pConjunctionAnd = p.get(Construct.conjunctionAnd);
        conjunctionBody.add(seq(lpar, primary, rpar, and, lpar, primary, rpar, rep(seq(and, lpar, primary, rpar), true, pConjunctionAnd )), pConjunctionAnd);
        conjunctionBody.add(primary, 1 - pConjunctionAnd);
        
        NonTerminal conjunction = nt("conjunction", conjunctionBody);
        
        Alt descriptionAlt      = new Alt();
        double pDescriptionOr   = p.get(Construct.descriptionOr);
        descriptionAlt.add(seq(lpar, conjunction, rpar, or, lpar, conjunction, rpar, rep(seq(or, lpar, conjunction, rpar), true, pDescriptionOr)), pDescriptionOr);
        descriptionAlt.add(conjunction, 1 - pDescriptionOr);
        
        //description.setSymbol(seq(conjunction, rep(seq(or, conjunction), true, p.get(Construct.descriptionOr))));
        description.setSymbol(descriptionAlt);
        
        NonTerminal objectPropertyFact = nt("objectPropertyFact", seq(objectPropertyIRI, individual));
        NonTerminal dataPropertyFact = nt("dataPropertyFact", seq(dataPropertyIRI, literal));
        
        Alt factBody    = new Alt();
        factBody.add(objectPropertyFact, p.get(Construct.factObjectProperty));
        factBody.add(dataPropertyFact, p.get(Construct.factDataProperty));
        
        NonTerminal fact        = nt("fact", seq(opt(not, p.get(Construct.factNot)), factBody));
        NonTerminal factsList   = nt("factsList", list(fact, comma, p.get(Construct.listNext)));
        
        Alt classFrameBody              = new Alt();
        classFrameBody.add(seq(subClassOf, descriptionList), p.get(Construct.classFrameSubClassOf));
        classFrameBody.add(seq(equivalentTo, descriptionList), p.get(Construct.classFrameEquivalentTo));
        classFrameBody.add(seq(disjointWith, classIRI), p.get(Construct.classFrameDisjointWith));
        classFrameBody.add(seq(disjointUnionOf, classIRIList), p.get(Construct.classFrameDisjointUnionOf));
        
        NonTerminal classFrame  = nt("classFrame", seq(classT, classIRI, classFrameBody));
        
        Alt objectPropertyCharacteristics   = new Alt();
        objectPropertyCharacteristics.add(functional, p.get(Construct.objectPropertyCharacteristicsFunctional));
        objectPropertyCharacteristics.add(inverseFunctional, p.get(Construct.objectPropertyCharacteristicsInverseFunctional));
        objectPropertyCharacteristics.add(reflexive, p.get(Construct.objectPropertyCharacteristicsReflexive));
        objectPropertyCharacteristics.add(irreflexive, p.get(Construct.objectPropertyCharacteristicsIrreflexive));
        objectPropertyCharacteristics.add(symmetric, p.get(Construct.objectPropertyCharacteristicsSymmetric));
        objectPropertyCharacteristics.add(asymmetric, p.get(Construct.objectPropertyCharacteristicsAsymmetric));
        objectPropertyCharacteristics.add(transitive, p.get(Construct.objectPropertyCharacteristicsTransitive));

        NonTerminal objectPropertyCharacteristicList    = nt("objectPropertyCharacteristicsList", list(objectPropertyCharacteristics, comma, p.get(Construct.listNext)));
        
        Alt objectPropertyFrameBody     = new Alt();
        objectPropertyFrameBody.add(seq(domain, descriptionList), p.get(Construct.objectPropertyFrameDomain));
        objectPropertyFrameBody.add(seq(range, descriptionList), p.get(Construct.objectPropertyFrameRange));
        objectPropertyFrameBody.add(seq(characteristics, objectPropertyCharacteristicList), p.get(Construct.objectPropertyFrameCharacteristics));
        objectPropertyFrameBody.add(seq(subPropertyOf, objectPropertyExpressionList), p.get(Construct.objectPropertyFrameSubPropertyOf));
        objectPropertyFrameBody.add(seq(equivalentTo, objectPropertyExpressionList), p.get(Construct.objectPropertyFrameEquivalentTo));
        objectPropertyFrameBody.add(seq(disjointWith, objectPropertyExpressionList), p.get(Construct.objectPropertyFrameDisjointWith));
        objectPropertyFrameBody.add(seq(inverseOf, objectPropertyExpressionList), p.get(Construct.objectPropertyFrameInverseOf));
        objectPropertyFrameBody.add(seq(subPropertyChain, objectPropertyExpression, rep(seq(o, objectPropertyExpression), false, p.get(Construct.subPropertyChainNext))), p.get(Construct.objectPropertyFrameSubPropertyChain));

        NonTerminal objectPropertyFrame = nt("objectPropertyFrame", seq(objectProperty, objectPropertyIRI, objectPropertyFrameBody));
        
        
        Alt dataPropertyFrameBody       = new Alt();
        dataPropertyFrameBody.add(seq(domain, descriptionList), p.get(Construct.dataPropertyFrameDomain));
        dataPropertyFrameBody.add(seq(range, dataRangeList), p.get(Construct.dataPropertyFrameRange));
        dataPropertyFrameBody.add(seq(characteristics, functional), p.get(Construct.dataPropertyFrameCharacteristics));
        dataPropertyFrameBody.add(seq(subPropertyOf, dataPropertyExpressionList), p.get(Construct.dataPropertyFrameSubPropertyOf));
        dataPropertyFrameBody.add(seq(equivalentTo, dataPropertyExpressionList), p.get(Construct.dataPropertyFrameEquivalentTo));
        dataPropertyFrameBody.add(seq(disjointWith, dataPropertyExpressionList), p.get(Construct.dataPropertyFrameDisjointWith));
        
        NonTerminal dataPropertyFrame = nt("dataPropertyFrame", seq(dataProperty, dataPropertyIRI, dataPropertyFrameBody));
        
        Alt individualFrameBody         = new Alt();
        individualFrameBody.add(seq(types, descriptionList), p.get(Construct.individualFrameTypes));
        individualFrameBody.add(seq(facts, factsList), p.get(Construct.individualFrameFacts));
        individualFrameBody.add(seq(sameAs, individualList), p.get(Construct.individualFrameSameAs));
        individualFrameBody.add(seq(differentFrom, individualList), p.get(Construct.individualFrameDifferentFrom));
        
        NonTerminal individualFrame = nt("individualFrame", seq(individualT, individual, individualFrameBody));
        
        
//        Alt miscBody    = new Alt();
//        miscBody.add(seq(equivalentClasses, description2List), p.get(Construct.miscEquivalentClasses));
//        miscBody.add(seq(disjointClasses, description2List), p.get(Construct.miscDisjointClasses));
//        miscBody.add(seq(equivalentProperties, objectProperty2List), p.get(Construct.miscEquivalentProperties));
//        miscBody.add(seq(disjointProperties, objectProperty2List), p.get(Construct.miscDisjointProperties));
//        miscBody.add(seq(equivalentProperties, dataProperty2List), p.get(Construct.miscEquivalentDataProperties));
//        miscBody.add(seq(disjointProperties, dataProperty2List), p.get(Construct.miscDisjointDataProperties));
//        miscBody.add(seq(sameIndividual, individual2List), p.get(Construct.miscSameIndividual));
//        miscBody.add(seq(differentIndividuals,individual2List), p.get(Construct.miscDifferentIndividual));
        
//        NonTerminal misc    = nt("misc", miscBody);
        
        Alt frameBody    = new Alt();
        frameBody.add(classFrame, p.get(Construct.classFrame));
        frameBody.add(objectPropertyFrame, p.get(Construct.objectPropertyFrame));
        frameBody.add(dataPropertyFrame, p.get(Construct.dataPropertyFrame));
        frameBody.add(individualFrame, p.get(Construct.individualFrame));
//        frameBody.add(misc, p.get(Construct.misc));
        
        frame           = nt("frame", frameBody);
        
        dataType.setOnetoUniformPropability();
        objectPropertyExpressionBody.setOnetoUniformPropability();
        facetBody.setOnetoUniformPropability();        
        dataAtomicBody.setOnetoUniformPropability();
        restrictionBody.setOnetoUniformPropability();
        atomicBody.setOnetoUniformPropability();
        primaryAlt.setOnetoUniformPropability();
        conjunctionBody.setOnetoUniformPropability();
        factBody.setOnetoUniformPropability();
        classFrameBody.setOnetoUniformPropability();        
        objectPropertyCharacteristics.setOnetoUniformPropability();
        objectPropertyFrameBody.setOnetoUniformPropability();
        dataPropertyFrameBody.setOnetoUniformPropability();
        individualFrameBody.setOnetoUniformPropability();
//        miscBody.setOnetoUniformPropability();
        frameBody.setOnetoUniformPropability();
        
    }
         
}
